package com.oron3.lock;


import java.util.ArrayList;
import java.util.List;

import android.app.NotificationManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.sqlite.SQLiteDatabase;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.support.v4.content.LocalBroadcastManager;

import com.ofek.applicationbase.forms.Broadcaster;
import com.ofek.applicationbase.utils.Delegate;
import com.ofek.applicationbase.utils.Log;
import com.ofek.db.Table;

public class LockDatabaseService extends Service {
	private Looper looper;
	private Handler handler;
	private Table<Secret> db;
	public static final String SECRET_NOTIFY_DATA_SET_CHANGED = LockDatabaseService.class.getName()+".EVENT_NOTIFY_DATA_SET_CHANGED";
	public static final String SECRET_REMOVE_REQUEST = LockDatabaseService.class.getName()+".EVENT_REMOVE_REQUEST";
	public static final String SECRET_EXTRA = LockDatabaseService.class.getName()+".SECRET_EXTRA";


	public enum State {
		PROCESSING,
		IDLE
	}
	public interface StateListener {
		/**
		 * Called whenever the state of the SessionBuilder is changed and when first registered.
		 * <br>Running from some thread (most likely not the ui thread)
		 * @param s
		 */
		public void onStateUpdated(State s);
	}

	private final ArrayList<StateListener> listeners = new ArrayList<StateListener>();
	private State currentState = State.IDLE;
	private LocalBroadcastManager instance;
	private Handler internetHandler;

	private void setState(final State newState) {
		synchronized (currentState) {
			currentState = newState;
		}
		synchronized (listeners) {
			for (final StateListener sl : listeners) {
				sl.onStateUpdated(newState);
			}
		}
	}


	public State getState() { 
		synchronized (currentState) {
			return currentState;
		} 
	}

	@Override
	public void onCreate() {
		Log.d("onCreate");
		super.onCreate();
		instance = LocalBroadcastManager.getInstance(this);
		instance.registerReceiver(new BroadcastReceiver() {

			@Override
			public void onReceive(final Context context,
					final Intent intent) {
				final Secret event = (Secret) intent.getSerializableExtra(SECRET_EXTRA);
				remove(event);
			}

		}, new IntentFilter(SECRET_REMOVE_REQUEST));

		final HandlerThread handlerThread = new HandlerThread("EventosService");
		final HandlerThread internetThread = new HandlerThread("EventosRemote");
		handlerThread.start();
		internetThread.start();
		looper = handlerThread.getLooper();
		handler = new Handler(looper);
		internetHandler = new Handler(internetThread.getLooper());
		final SQLiteDatabase sqldb = openOrCreateDatabase("Lock", MODE_PRIVATE, null);
		sqldb.execSQL("PRAGMA foreign_keys=ON;");
		db = new Table<Secret>(sqldb, Secret.class);

		//.openOrCreateDatabase(,;
		//Application.MODE_PRIVATE, null);


	}








	@Override
	public int onStartCommand(final Intent intent, final int flags, final int startId) {
		Log.d("onStartCommand");

		//				internetHandler.post(new Runnable() {
		//		
		//		
		//		
		//					@Override
		//					public void run() {
		//						try {
		//							final P2PEndPoint dbSyncer = new P2PEndPoint(Constants.EVENTOS_DB_FILE,  Constants.SERVER_IP+":12384", 5);
		//							dbSyncer.start();
		//							//					debugSyncer = new P2PEndPoint(Constants.EVENTOS_DEBUG_FILE, "192.168.2.109:12385", 5);
		//							//					pp.start();
		//						} catch (final IOException e) {
		//							e.printStackTrace();
		//						}
		//					}
		//				});
		return START_STICKY;
	}
	@Override
	public void onDestroy() {
		Log.d("onDestroy");
		super.onDestroy();
		cancelNotification();
	}
	@Override
	public IBinder onBind(final Intent arg0) {
		return new LockServiceBinder();
	}
	public class LockServiceBinder extends Binder {
		public LockDatabaseService getLockDatabaseService() {
			return LockDatabaseService.this;
		}
	}

	private void cancelNotification() {
		final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		notificationManager.cancel(1);
	}

	public static interface DataListener {
		public void onUpdate(Secret older, Secret newer);
		public void onAddition(Secret added);
		public void onRemoval(Secret removed);
		public void onAddition(List<Secret> all);
	}
	private final Broadcaster<DataListener> broadcater = new Broadcaster<LockDatabaseService.DataListener>();
	public boolean registerDataListener(final DataListener listener) {
		return broadcater.register(listener);
	}
	public void add(final Secret secret) {
		handler.post(new Runnable() {

			@Override
			public void run() {
				setState(State.PROCESSING);
				db.add(secret);
				broadcater.broadcast(new Delegate<LockDatabaseService.DataListener>() {

					@Override
					public void invoke(final DataListener t) {
						t.onAddition(secret);
					}
				});
				instance.sendBroadcast(new Intent(SECRET_NOTIFY_DATA_SET_CHANGED));
				setState(State.IDLE);
			}
		});
	}

	public void remove(final Secret secret) {
		handler.post(new Runnable() {

			@Override
			public void run() {
				setState(State.PROCESSING);
				db.remove(secret);
				broadcater.broadcast(new Delegate<LockDatabaseService.DataListener>() {

					@Override
					public void invoke(final DataListener t) {
						t.onRemoval(secret);
					}
				});
				instance.sendBroadcast(new Intent(SECRET_NOTIFY_DATA_SET_CHANGED));
				setState(State.IDLE);
			}
		});
	}





	public void update(final Secret secret) {
		handler.post(new Runnable() {

			@Override
			public void run() {
				setState(State.PROCESSING);
				final Secret old = db.get(new Secret(secret.sid));
				db.update(secret);
				final Secret nu = db.get(new Secret(secret.sid));
				broadcater.broadcast(new Delegate<LockDatabaseService.DataListener>() {
					@Override
					public void invoke(final DataListener t) {
						t.onUpdate(old,nu);
					}
				});
				instance.sendBroadcast(new Intent(SECRET_NOTIFY_DATA_SET_CHANGED));
				setState(State.IDLE);
			}
		});
	}




	public void addAll(final ArrayList<Secret> all) {
		handler.post(new Runnable() {

			@Override
			public void run() {
				setState(State.PROCESSING);
				db.addAll(all);
				broadcater.broadcast(new Delegate<LockDatabaseService.DataListener>() {

					@Override
					public void invoke(final DataListener t) {
						t.onAddition(all);
					}
				});
				instance.sendBroadcast(new Intent(SECRET_NOTIFY_DATA_SET_CHANGED));
				setState(State.IDLE);
			}
		});
	}



	public void getAll(final Delegate<ArrayList<Secret>> toDo) {
		handler.post(new Runnable() {

			@Override
			public void run() {
				setState(State.PROCESSING);
				toDo.invoke(db.getAll());
				setState(State.IDLE);
			}
		});
	}


	public void unregisterDataListener(final DataListener listener) {
		broadcater.unregister(listener);
	}
}
